package com.hjq.demo.aop

import android.os.Trace
import com.flyjingfish.android_aop_annotation.ProceedJoinPoint
import com.flyjingfish.android_aop_annotation.base.BasePointCut
import timber.log.Timber
import java.util.Arrays
import java.util.concurrent.TimeUnit

class LogCut : BasePointCut<Log> {
    override fun invoke(
        joinPoint: ProceedJoinPoint,
        annotation: Log //annotation就是你加到方法上的注解
    ): Any? {

        enterMethod(joinPoint, annotation)
        val startNanos: Long = System.nanoTime()
        val result: Any? = joinPoint.proceed()
        val stopNanos: Long = System.nanoTime()
        exitMethod(joinPoint, annotation, result, TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos))

        return result
    }


    /**
     * 方法执行前切入
     */
    private fun enterMethod(joinPoint: ProceedJoinPoint, log: Log) {
        // 方法所在类
        val className: String = joinPoint.getTargetClass().name
        // 方法名
        val methodName: String = joinPoint.targetMethod.name
        // 记录并打印方法的信息
        val builder = StringBuilder("\u21E2 ")
            .append(className)
            .append(".")
            .append(methodName)
        log(log.value, builder.toString())
        val section: String = builder.substring(2)
        Trace.beginSection(section)
    }

    /**
     * 方法执行完毕，切出
     *
     * @param result            方法执行后的结果
     * @param lengthMillis      执行方法所需要的时间
     */
    private fun exitMethod(
        joinPoint: ProceedJoinPoint,
        log: Log,
        result: Any?,
        lengthMillis: Long
    ) {
        Trace.endSection()
        val className: String? = joinPoint.getTargetClass().name
        val methodName: String? = joinPoint.targetMethod.name
        val builder: StringBuilder = StringBuilder("\u21E0 ")
            .append(className)
            .append(".")
            .append(methodName)
            .append(" [")
            .append(lengthMillis)
            .append("ms]")

        //  判断方法是否有返回值
        if (joinPoint.targetMethod.returnType != Void.TYPE) {
            builder.append(" = ")
            builder.append(result.toString())
        }
        log(log.value, builder.toString())
    }

    private fun log(tag: String?, msg: String?) {
        Timber.tag(tag)
        Timber.d(msg)
    }
}